package me.whf.dao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import me.whf.dao.factory.DAOFactory;
import me.whf.model.Account;
import me.whf.model.AdvanceAccount;
import me.whf.model.EnterpriseMapping;
import me.whf.util.Utils;
import me.whf.util.Utils.UserType;

public class FileAccountDAO implements AccountDAO {

	public boolean isExisted(String accountID) {
		return Utils.accounts.containsKey(accountID);
	}

	public boolean createAccount(Account account) {
		// 如果时企业用户的话，抹掉password，然后添加到两个表当中
		if (account.getUserType() == UserType.COMMON)
			Utils.accounts.put(account.getId(), account);
		else if (account.getUserType() == UserType.VIP) {
			if (account.getBalance() < 1000000)
				return false;
			AdvanceAccount advanceAccount = new AdvanceAccount(account.getId(), false, 0, 0, 0);
			Utils.accounts.put(account.getId(), account);
			Utils.vipstuff.put(account.getId(), advanceAccount);
		} else {
			EnterpriseMapping mapping = new EnterpriseMapping(account.getIdentity(), true, account.getPassword());
			account.setPassword("");
			
			ArrayList<EnterpriseMapping> enterprise = new ArrayList<EnterpriseMapping>();
			enterprise.add(mapping);
			
			Utils.accounts.put(account.getId(), account);
			Utils.enterprises.put(account.getId(), enterprise);
		}
		return true;
	}

	public boolean deposit(String accountID, String password, double money) {
		Account account = Utils.accounts.get(accountID);
		
		if (account != null) {
			if (account.getUserType() == UserType.COMMON && account.getPassword().equals(password)) {
				account.setBalance(account.getBalance() + money);
				Utils.accounts.put(accountID, account);
				return true;
			} else if (account.getUserType() == UserType.VIP && account.getPassword().equals(password)) {
				account.setBalance(account.getBalance() + money);
				Utils.accounts.put(accountID, account);
				
				double balance = query(accountID, password);
				if (balance >= 0) {
					refund(accountID);
					unFrozen(accountID);
				}
				return true;
			} else if (account.getUserType() == UserType.ENTERPRISE) {
				ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
				boolean staff = false;
				for (EnterpriseMapping people: enterprise) {
					if (people.getPassword().equals(password)) {
						staff = true;
						break;
					}
				}
				if (staff) {
					account.setBalance(account.getBalance() + money);
					Utils.accounts.put(accountID, account);
					return true;
				}
			}
		} 
		return false;
	}

	public double query(String accountID, String password) {
		Account account = Utils.accounts.get(accountID);
		
		if (account != null && account.getUserType() != UserType.ENTERPRISE && account.getPassword().equals(password)) {
			return account.getBalance();
		} else if (account != null && account.getUserType() == UserType.ENTERPRISE) {
			ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
			boolean staff = false;
			for (EnterpriseMapping people: enterprise) {
				if (people.getPassword().equals(password)) {
					staff = true;
					break;
				}
			}
			if (staff) {
				return account.getBalance();
			}
		}
		return Integer.MIN_VALUE;
	}

	public boolean withdraw(String accountID, String password, double money) {
		Account account = Utils.accounts.get(accountID);
		
		if (account != null && account.getUserType() == UserType.COMMON && account.getPassword().equals(password)) {
			account.setBalance(account.getBalance() - money);
			Utils.accounts.put(accountID, account);
			return true;
		} else if (account != null && account.getUserType() == UserType.VIP && account.getPassword().equals(password)) {
			if (!loanFrozenCheck(accountID)) {
				account.setBalance(account.getBalance() - money);
				Utils.accounts.put(accountID, account);
				
				double balance = query(accountID, password);
				if (balance < 0) {
					loan(accountID);
				}
				return true;
			}
			return false;
		} else if (account != null && account.getUserType() == UserType.ENTERPRISE) {
			ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
			boolean staff = false;
			for (EnterpriseMapping people: enterprise) {
				if (people.getPassword().equals(password)) {
					staff = true;
					break;
				}
			}
			if (staff) {
				account.setBalance(account.getBalance() - money);
				Utils.accounts.put(accountID, account);
				return true;
			}
		}
		return false;
	}

	public double query(String identity, String accountID, String password) {
		Account account = Utils.accounts.get(accountID);
		
		if (account != null && account.getUserType() != UserType.ENTERPRISE &&
				account.getPassword().equals(password) && account.getIdentity().equals(identity)) {
			return account.getBalance();
		} else if (account != null && account.getUserType() == UserType.ENTERPRISE) {
			ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
			boolean staff = false;
			for (EnterpriseMapping people: enterprise) {
				if (people.getPassword().equals(password) && people.getEnterpriseID().equals(identity)) {
					staff = true;
					break;
				}
			}
			if (staff) {
				return account.getBalance();
			}
		}
		return Integer.MIN_VALUE;
	}

	public boolean transfer(String accountID, String identity, String password,
			String username, String receiverAccountID, String receiverUsername,
			double money) {
		Account account = Utils.accounts.get(accountID);
		Account receiverAccount = Utils.accounts.get(receiverAccountID);
		
		if (account == null || receiverAccount == null)
			return false;
		
		boolean canTransfer = true;
		if (!account.getUserType().equals(receiverAccount.getUserType()) && 
				(account.getUserType().equals(UserType.ENTERPRISE) || 
						receiverAccount.getUserType().equals(UserType.ENTERPRISE)))
			canTransfer = false;
		if (account.getUserType().equals(UserType.COMMON) && 
				!account.getUsername().equals(receiverAccount.getUsername())) 
			canTransfer = false;
		
		if (canTransfer && account.getUserType() != UserType.ENTERPRISE && account.getIdentity().equals(identity) &&
				account.getPassword().equals(password) && account.getUsername().equals(username) &&
				receiverAccount.getUsername().equals(receiverUsername)) {
			if (account.getUserType() == UserType.VIP) {
				if (!loanFrozenCheck(accountID)) {
					account.setBalance(account.getBalance() - money);
					Utils.accounts.put(accountID, account);
					receiverAccount.setBalance(receiverAccount.getBalance() + money);
					Utils.accounts.put(receiverAccountID, receiverAccount);
					
					double balance = query(accountID, password);
					if (balance < 0) {
						loan(accountID);
					}
					return true;
				}
				return false;
			} else {
				account.setBalance(account.getBalance() - money);
				Utils.accounts.put(accountID, account);
				receiverAccount.setBalance(receiverAccount.getBalance() + money);
				Utils.accounts.put(receiverAccountID, receiverAccount);
				return true;
			}
		} else if (canTransfer && account.getUserType() == UserType.ENTERPRISE && account.getIdentity().equals(identity) &&
				account.getUsername().equals(username) && receiverAccount.getUsername().equals(receiverUsername)) {
			ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
			boolean staff = false;
			for (EnterpriseMapping people: enterprise) {
				if (people.getPassword().equals(password)) {
					staff = true;
					break;
				}
			}
			if (staff) {
				account.setBalance(account.getBalance() - money);
				Utils.accounts.put(accountID, account);
				
				receiverAccount.setBalance(receiverAccount.getBalance() + money);
				Utils.accounts.put(receiverAccountID, receiverAccount);
				return true;
			}
		}
		return false;
	}

	public boolean changePassword(String identity, String accountID,
			String oldPassword, String password) {
		Account account = Utils.accounts.get(accountID);
		
		if (account != null && account.getUserType() != UserType.ENTERPRISE && 
				account.getIdentity().equals(identity) && account.getPassword().equals(oldPassword)) {
			account.setPassword(password);
			Utils.accounts.put(accountID, account);
			return true;
		} else if (account != null && account.getUserType() == UserType.ENTERPRISE && account.getIdentity().equals(identity)) {
			ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
			EnterpriseMapping staff = null;
			for (EnterpriseMapping people: enterprise) {
				if (people.getPassword().equals(password)) {
					staff = people;
					break;
				}
			}
			if (staff != null) {
				enterprise.remove(staff);
				staff.setPassword(password);
				enterprise.add(staff);
				Utils.enterprises.put(accountID, enterprise);
			}
		}
		return false;
	}
	
	public boolean addEnterpriseOperator(String accountID, String enterpriseIdentity, String ownerPassword, String operatorPassword) {
		ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
		boolean isOwn = false;
		
		if (enterprise == null)
			return false;
		
		for (EnterpriseMapping staff: enterprise) {
			if (staff.getPassword().equals(ownerPassword) && staff.isManager() == true && 
					staff.getEnterpriseID().equals(enterpriseIdentity))
				isOwn = true;
		}
		if (isOwn) {
			EnterpriseMapping mapping = new EnterpriseMapping(enterpriseIdentity, false, operatorPassword);
			enterprise.add(mapping);
			Utils.enterprises.put(accountID, enterprise);
			return true;
		}
		return false;
	}

	public boolean destory(String identity, String accountID, String password) {
		Account account = Utils.accounts.get(accountID);
		
		if (account != null && account.getUserType() != UserType.ENTERPRISE && 
				account.getIdentity().equals(identity) && account.getPassword().equals(password)) {
			Utils.accounts.remove(accountID);
			return true;
		} else if (account != null && account.getUserType() == UserType.ENTERPRISE && account.getIdentity().equals(identity)) {
			ArrayList<EnterpriseMapping> enterprise = Utils.enterprises.get(accountID);
			boolean staff = false;
			for (EnterpriseMapping people: enterprise) {
				if (people.getPassword().equals(password) && people.isManager()) {
					staff = true;
					break;
				}
			}
			if (staff) {
				Utils.accounts.remove(accountID);
				Utils.enterprises.remove(accountID);
			}
		}
		return false;
	}
	
	public boolean canWithdraw(String accountID, String password, double money) {
		Account account = Utils.accounts.get(accountID);
		if (account == null)
			return false;
		
		UserType userType = account.getUserType();
		if (userType == UserType.COMMON) {
			if (query(accountID, password) >= money)
				return true;
			else
				return false;
		} else if (userType == UserType.VIP) {
			if (query(accountID, password) - money >= -100000)
				return true;
			else
				return false;
		} else {
			if (query(accountID, password) - money >= 10000)
				return true;
			else
				return false;
		}
	}
	
	/**
	 * VIP loan
	 * */
	public void loan(String accountID) {
		AdvanceAccount advanceAccount = Utils.vipstuff.get(accountID);
		if (advanceAccount.getBorrowDays() != 0)
			advanceAccount.setBorrowDays(1);
		Utils.vipstuff.put(accountID, advanceAccount);
	}
	
	/**
	 * VIP daily settlement
	 * */
	public void dailySettlement() {
		Map<String, AdvanceAccount> temp = new HashMap<String, AdvanceAccount>();
		
		Iterator iterator = Utils.vipstuff.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry entry = (Entry) iterator.next();
			AdvanceAccount advanceAccount = (AdvanceAccount) entry.getValue();
			
			Account account = Utils.accounts.get(advanceAccount.getAccountID());
			advanceAccount.setMonthBalanceSum(advanceAccount.getMonthBalanceSum() + account.getBalance());
			
			if (advanceAccount.getBorrowDays() != 0) {
				advanceAccount.setBorrowDays(advanceAccount.getBorrowDays() + 1);
			}
			if (advanceAccount.getBorrowDays() >= 30) {
				advanceAccount.setFrozen(true);
			}
			temp.put(advanceAccount.getAccountID(), advanceAccount);
		}
		Utils.vipstuff.clear();
		Utils.vipstuff.putAll(temp);
	}
	
	/**
	 * VIP refund
	 * */
	public void refund(String accountID) {
		AdvanceAccount advanceAccount = Utils.vipstuff.get(accountID);
		advanceAccount.setBorrowDays(0);
		Utils.vipstuff.put(accountID, advanceAccount);
	}
	
	/**
	 * VIP month settlement
	 * */
	public void monthSettlement() {
		Map<String, AdvanceAccount> temp = new HashMap<String, AdvanceAccount>();
		
		Iterator iterator = Utils.vipstuff.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry entry = (Entry) iterator.next();
			AdvanceAccount advanceAccount = (AdvanceAccount) entry.getValue();
			
			if (advanceAccount.getMonthBalanceSum() / 30 < 100000) {
				advanceAccount.setLowMonth(advanceAccount.getLowMonth() + 1);
			} else {
				advanceAccount.setLowMonth(0);
			}
			if (advanceAccount.getLowMonth() >= 2) {
				LoggerDAO loggerDAO = DAOFactory.getDAOFactory().getLoggerDAO();
				loggerDAO.log("admin", "VIP用户月结连续两个月以上少于10万", advanceAccount.getAccountID());
				
				Account account = Utils.accounts.get(advanceAccount.getAccountID());
				account.setBalance(account.getBalance() - 1000);
				Utils.accounts.put(advanceAccount.getAccountID(), account);
				advanceAccount.setMonthBalanceSum(account.getBalance());
			}
			temp.put(advanceAccount.getAccountID(), advanceAccount);
		}
		Utils.vipstuff.clear();
		Utils.vipstuff.putAll(temp);
	}
	
	/**
	 * VIP check frozen or not
	 * */
	public boolean loanFrozenCheck(String accountID) {
		AdvanceAccount advanceAccount = Utils.vipstuff.get(accountID);
		return advanceAccount.isFrozen();
	}
	
	/**
	 * VIP bring the account to alive
	 * */
	public void unFrozen(String accountID) {
		AdvanceAccount advanceAccount = Utils.vipstuff.get(accountID);
		advanceAccount.setFrozen(false);
		Utils.vipstuff.put(advanceAccount.getAccountID(), advanceAccount);
	}
}
